
Mapper = function() {};

Mapper.prototype = {

  lon: 0,
  lat: 0,
  zoom: 2,
  updateme: true,
  map: null,
  layer: null,
  markers: null,
  mapdivnode: null,
  click: false,
  hover: null,
  uid: "map",

  // add visual art
  add_point: function(lon,lat,descr,artwork) {

    if(!this.map || !lon || !lat || !descr) {
      return;
    }

    // stand in artwork handling for now
    var artwork = "/appwiki/map/icons/emblem-favorite.png";
    if( descr.indexOf(":-)") == 0 )
      artwork = "/appwiki/map/icons/face-smile.png";
    else if( descr.indexOf(":-|") == 0 )
      artwork = "/appwiki/map/icons/face-plain.png";
    else if( descr.indexOf(":-(") == 0 )
      artwork = "/appwiki/map/icons/face-sad.png";
    else if( descr.indexOf(":-D") == 0 )
      artwork = "/appwiki/map/icons/face-smile-big.png";
    else if( descr.indexOf(":-o") == 0 )
      artwork = "/appwiki/map/icons/face-surprise.png";
    else if( descr.indexOf(";-)") == 0 )
      artwork = "/appwiki/map/icons/face-wink.png";
    else if( descr.indexOf(":-*") == 0 )
      artwork = "/appwiki/map/icons/face-kiss.png";
    else if( descr.indexOf(":-)") == 0 )
      artwork = "/appwiki/map/icons/face-smile.png";
    else if( descr.indexOf(":-)") == 0 )
      artwork = "/appwiki/map/icons/face-smile.png";
    else if( descr.indexOf(":-)") == 0 )
      artwork = "/appwiki/map/icons/face-smile.png";
    else if( descr.indexOf(":-)") == 0 )
      artwork = "/appwiki/map/icons/face-smile.png";

    var lonlat = new OpenLayers.LonLat(lon,lat);
    var textsz = new OpenLayers.Size(100,15);
    var iconsz = new OpenLayers.Size(32,32); 
    var icon   = new OpenLayers.Icon(artwork,iconsz);
    var marker = new OpenLayers.Marker(lonlat,icon);

    // openlayers stuff
    var xfocus = this;
    this.markers.addMarker(marker);
    marker.events.register("mouseover",marker, function() {
      if(!xfocus.hover) {
        xfocus.hover = new OpenLayers.Popup.Anchored("myuniqueid",
                             lonlat,
                             textsz,
                             descr
                            );
        //xfocus.hover = document.createElement("div");
        //xfocus.hover.style.position = 'absolute';
        //xfocus.hover.style.width = "100px";
        //xfocus.hover.style.height = "10px";
        //xfocus.hover.style.border = "2px solid red";
        //xfocus.mapdivnode.appendChild(xfocus.hover);
        xfocus.map.addPopup(xfocus.hover);
      } else {
      }
      //xfocus.hover.style.display = "visible";
      //xfocus.hover.style.left = "40px";
      //xfocus.hover.style.top = "50px";
      //xfocus.hover.style.innerHTML = "a marker";
    } );

    // more openlayers stuff
    marker.events.register("mouseout",marker,function() {
      if(xfocus.hover) {
        xfocus.map.removePopup(xfocus.hover);
        xfocus.hover = null; // xxx something horrible with removepopup trashing state
        //xfocus.hover.style.display = "none";
      }
    } );

    // all done
  },


  // when content is posted to db from client; sometimes we map it if it is interesting
  // xxx it is arguable that this should mostly be done by a smarter server.
  database_listen: function(e) {

    // look at certain kinds of things only
    if(!e || !e.title) {
      return;
    }

    // go somewhere; may geocode
    if( e.title.indexOf('/map goto')==0 && e.handler=='chat' ) {
      // xxx write this; should do on server or client? may want to start moving to server here
      return;
    }

    // store a mappable object if a comment requests it
    if( e.title.indexOf('/map')==0 && e.handler=='chat' ) {

      // touch the item with the map current focus
      var center = this.map.getCenter();
      e.lat = center.lat.toString();
      e.lon = center.lon.toString();

      // store our own copy
      DatabaseStore(this,this.uid+"/#",{title:e.title,handler:'map',lat:e.lat,lon:e.lon} );
      return;
    }

  },

  // when an area has no content; just do nothing in particular
  database_update_empty: function(e) {
    if(this.updateme) {
      this.lon = 0;
      this.lat = 0;
      this.zoom = 1;
      //alert('defaulting to ' + this.lon + " " + this.lat + " " + this.zoom );
      this.map.events.remove("moveend");
      this.map.setCenter(new OpenLayers.LonLat(this.lon, this.lat), this.zoom);
      this.map.events.register("moveend", this, this.event_moved );
      this.updateme = false;
    }
  },

  // update display with new item
  database_update: function(e) {

    if(!e) return;
    if(e.handler == "state") {
      this.lat = e.lat;
      this.lon = e.lon;
      this.zoom = e.zoom;
      this.updateme = true;
    } else {
      this.add_point(e.lon,e.lat,e.title,e.artwork);
    }

    // updated?
    // this also handles the first refresh so that it appears in the right spot
    if(this.updateme) {
      //alert('moving to ' + this.lon + " " + this.lat + " " + this.zoom );
      this.map.events.remove("moveend");
      this.map.setCenter(new OpenLayers.LonLat(this.lon, this.lat), this.zoom);
      this.map.events.register("moveend", this, this.event_moved );
      this.updateme = false;
    }
  },

  // handle map moved
  event_moved: function() {
    var center = this.map.getCenter();
    var zoom = this.map.getZoom();
    if(center.lat && center.lon && zoom) {
      var f = new Object();
      f.handler = "state";
      f.lat = center.lat.toString();
      f.lon = center.lon.toString();
      f.zoom = zoom;
      f.title = "/map goto " + f.lat + " " + f.lon + " " + f.zoom;
      DatabaseStore(this,"state",f);
    }
  },

  // start
  startup: function(node) {

    // where to store posts
    this.uid = "map";

    // make map
    this.mapdivnode = node;
    this.map = new OpenLayers.Map( node );
    this.layer = new OpenLayers.Layer.WMS( "OpenLayers WMS","http://labs.metacarta.com/wms-c/Basic.py?", {layers: 'basic', format: 'image/png' } );
    this.map.addLayer(this.layer);
    this.markers = new OpenLayers.Layer.Markers("Some points of interest");
    this.map.addLayer(this.markers);

    // listen to map events
    this.map.events.register("moveend", this, this.event_moved );

    // listen to local database events
    DatabaseListen(this);

    // specifically get the location
    DatabaseGet(this,"state","handler=state");

    // start synchronizing with the database - it calls local database_update() method eventually
    DatabaseSubscribe( this, 'map' );

    return this;
  },

  // stop
  shutdown: function() {
  },

}

Mapper.make = function(arg) {
  return (new Mapper()).startup(arg);
}


/* vector layer tests
    this.layer = new OpenLayers.Layer.Vector( "Vector Test Layer" );
    this.map.addLayer(this.layer);
    var marker = new OpenLayers.Marker(
                    new OpenLayers.LonLat(this.lon,this.lat),
                    new OpenLayers.Icon("http://openlayers.org/api/img/marker.png",new OpenLayers.Size(10,15))
                 );
    this.markers.addMarker(marker);
    var p1 = new OpenLayers.Vector.Point(new OpenLayers.LonLat(2.18, 43.0));
    var p2 = new OpenLayers.Vector.Point(new OpenLayers.LonLat(14.4, 49.29));
    var p3 = new OpenLayers.Vector.Point(new OpenLayers.LonLat(12.16, 37.39));
    var p4 = new OpenLayers.Vector.Point(new OpenLayers.LonLat(-71, 42.0));
    
    this.layer.addFeature(p1);
    this.layer.addFeature(p2);
    this.layer.addFeature(p3);
    this.layer.addFeature(p4);
    var line = new OpenLayers.Vector.Line(p1,p4);
    line.setStyle(new OpenLayers.Vector.CanvasStyle({'strokeStyle':'blue', 'lineWidth': 2, 'globalAlpha': .5}));  
    this.layer.addFeature(line);
    var line = new OpenLayers.Vector.Line(p1,p2);
    this.layer.addFeature(line);
    
    var poly = new OpenLayers.Vector.Polygon();
    poly.addLine(new OpenLayers.Vector.Line(p1, p2));
    poly.addLine(new OpenLayers.Vector.Line(p2, p3));
    poly.addLine(new OpenLayers.Vector.Line(p3, p1));
    this.layer.addFeature(poly);


    this.map.events.register("mousedown", this.map, function(e) {
      if (this.click) {
        //this.layer.addFeature(new OpenLayers.Vector.Line(this.click, new OpenLayers.Vector.Point(this.getLonLatFromPixel(e.xy))));
        this.click = null;
      } 
      else { 
        //this.click = new OpenLayers.Vector.Point(this.getLonLatFromPixel(e.xy));
      }
    });


 */
